home *** CD-ROM | disk | FTP | other *** search
- /* +-----------------------------------+
- * | |
- * | EVALX.C |
- * | |
- * +-----------------------------------+
- *
- * Algebraic Expression Evaluator/Parser
- *
- * James P. Hawkins - WA2WHV
- * P.O. Box 9146,
- * Trenton, NJ 08650
- *
- * calling format:
- *
- * double value;
- * double evalx();
- * value = evalx(expstr)
- *
- * where:
- * expstr is the char string representing the expression
- * to be evaluated. The string must be NULL terminated.
- * The expression may contain digits representing decimal numbers
- * or the following math functions:
- * sin(expstr) - sine of an angle in radians
- * cos(expstr) - cosine of an angle in radians
- * exp(expstr) - exponentiate
- * log(expstr) - natural log
- * int(expstr) - integerize (truncate to right of dec .)
- * sqr(expstr) - square root
- * abs(expstr) - absolute value
- * atn(expstr) - arctan
- * rnd(expstr) - random number gen
- * tan(expstr) - tangent of an angle
- * fact(expstr) - factorial
- * expression may contain the operators:
- * + addition
- * - subtraction
- * / division
- * * multiplication
- * () parenthesis (can be nested)
- * ^ exponentiate
- * Errors:
- * Test errorflg for non-zero;
- * See evalx.h for definitions of error constants.
- *
- */
- #include "evalx.h"
- #define STKSIZ 6 /* stack size */
-
- #define skipspace() {while(*expptr == ' ' || *expptr == '\t') *expptr++;}
-
- int errorflg = 0;
- char *eoexpr; /* Expression scan place holder */
-
- double pow();
- double atof();
- double mathcall();
-
-
- /* -------------------------------------------------------------------- */
- /*
- * Evaluate Expression - recursive
- * exps is pointer to ASCII expression string.
- */
- double evalx(char *exps)
- {
- char *expptr, /* expression string pointer */
- field[80]; /* expression field */
-
- int o, n, /* indicies for opstack & opndstack */
- savptr, /* save stack for pointer */
- type, /* field type returned by class */
- opflag; /* set when operator encountered
- cleared when variable or non-op
- encountered. Used to deal with
- unaries by forcing a 0.0 on the
- number stack */
-
- char opstack[STKSIZ]; /* operator stack */
- double opndstack[STKSIZ]; /* number stack */
-
-
- expptr = exps; /* init expression string pointer */
- o = n = STKSIZ; /* init operator and
- variable stack pointer */
- opflag = 0; /* init opflag */
-
- errorflg = 0;
-
- /*
- * Scan expression string until NULL is encountered.
- * Encounter of a paren calls this function recursively.
- * Encounter of recognized functions calls mathcall() which
- * determines which function to call based on the string name
- * of the function. The function may contain yet another
- * algebraic expression and so on.
- */
- while(*expptr != '\0')
- {
- if((type = class(&expptr, field)) < 0) /* get field and type */
- {
- errorflg = ERRSYNTAX; /* EXPR SYNTAX */
- errorflg = ERRFATAL; /* FATAL ERROR */
- return(0.0);/* return zero on error */
- }
-
- switch(type)
- {
- case NMCLASS: /* NUMERIC FIELD */
- opndstack[--n] = atof(field);
- opflag = 0;
- break;
- case FNCLASS: /* FUNCTION REFERENCE */
- opndstack[--n] = mathcall(field);
- opflag = 0;
- break;
- case OPCLASS: /* OPERATOR */
- switch(*field)
- {
- case '(': /* begin of expres */
- opndstack[--n] = evalx(expptr);
- opflag = 0;
- expptr = eoexpr; /* put pointer
- to correct place */
- break;
- case ')': /* end of express */
- /*
- * eval the rest of the expr
- * between the parens
- */
- cleanup(opndstack,opstack,&n,&o);
- eoexpr = expptr;
- return(opndstack[n]);
- break;
- case '+':
- case '-':
- case '*':
- case '/':
- case '^':
- /*
- * Handle unaries by forcing a 0.0 onto
- * the opndstack before stacking the operator.
- * This occurs when two operators in a row are
- * encountered or the variable stack is empty
- * when an operator encountered.
- */
- if(opflag || n == STKSIZ)
- opndstack[--n] = 0.0;
- opflag = 1;
- stackop(*field,opndstack,opstack,&n,&o);
- break;
- default:
- break;
- }
- break;
- default:
- errorflg = ERRILLVAR;
- break;
- }
- /*
- * Skip trailing white space so that
- * test at top of this loop fails when
- * it's supposed to.
- */
- skipspace();
- } /* END OF WHILE LOOP */
-
- cleanup(opndstack,opstack,&n,&o);
- eoexpr = expptr; /* Save place */
- return(opndstack[n]);
- }
-
- /* -------------------------------------------------------------------- */
- /*
- * //// STACK OPERATOR IF PRECIDENCE TEST IS PASSED ////
- */
- stackop(op,opndstack,opstack,n,o)
- char op;
- double opndstack[];
- char opstack[];
- int *n;
- int *o;
- {
-
- /*
- * If precedence of current operator is
- * HIGHER than the operator on top of the stack
- * or the OPERATOR stack is EMPTY,
- * the precedence test has "passed" so just push
- * the current operator onto the operator stack.
- */
- if(*o == STKSIZ) /* if stack is empty */
- {
- opstack[--(*o)] = op; /* stack operator
- precedence done only
- if stack NOT empty */
- return;
- }
- if(preced(op) > preced(opstack[*o]))
- {
- opstack[--(*o)] = op;
- }
- else
- {
- /*
- * OTHERWISE if the current operator
- * precedence is LESS than or EQUAL to the
- * operator on the top of the stack
- * "uopndstack" the operators from the operator
- * stack until either the stack is empty
- * or the precedence test passes
- */
- while((preced(op) <= preced(opstack[*o])) && *o < STKSIZ)
- {
- if(unstack(opndstack,opstack,n,o) < 0)
- {
- return(-1); /* break loop if bad operator
- encountered */
- }
- }
-
- opstack[--(*o)] = op;
- }
- }
-
- /* -------------------------------------------------------------------- */
- /*
- *
- * //// RETURN PRECEDENCE OF OPERATOR IN c ////
- */
- preced(c)
- char c;
- {
- static char olist[] = "+1-1*2/2^3"; /* list of operators & precedence */
- register int p; /* scanning register */
-
- for(p=0; olist[p] != '\0'; p += 2)
- {
- if(c == olist[p])
- {
- return(olist[p+1] - '0');
- }
- }
- return(-1); /* if we get here, we're in trouble! */
- }
-
- /* -------------------------------------------------------------------- */
- /*
- * //// CLEANUP THE REST OF THE EXPRESSION ////
- *
- * "pop and do" operations on opstack until
- * stack empty
- */
- cleanup(opndstack,opstack,n,o)
- double opndstack[];
- char opstack[];
- int *n;
- int *o;
- {
- while(*o < STKSIZ)
- {
- if(unstack(opndstack,opstack,n,o) < 0)
- {
- return(-1); /* break loop if bad operator
- encountered */
- }
- }
- }
-
- /* -------------------------------------------------------------------- */
- /*
- * This is where the actual math operations are performed.
- *
- * Pop operater off top of opstack and perform that operation on
- * the top two numbers on opndstack.
- * Opndstack gets popped and result is left on top.
- * Then POP both stacks.
- */
- unstack(opndstack,opstack,n,o)
- double opndstack[];
- char opstack[];
- int *n;
- int *o;
- {
- switch(opstack[*o])
- {
- case '^': /* Exponentiate */
- opndstack[*n+1] = pow(opndstack[*n+1],opndstack[*n]);
- break;
- case '*': /* Multiply */
- opndstack[*n+1] = opndstack[*n+1] * opndstack[*n];
- break;
- case '/': /* Divide */
- if(opndstack[*n] == 0.0) /* catch overflow */
- {
- errorflg = ERROVFLOW; /* OVERFLOW ERR */
- break;
- }
- opndstack[*n+1] = opndstack[*n+1] / opndstack[*n];
- break;
- case '+': /* Add */
- opndstack[*n+1] = opndstack[*n+1] + opndstack[*n];
- break;
- case '-': /* Subtract */
- opndstack[*n+1] = opndstack[*n+1] - opndstack[*n];
- break;
- default: /* Shouldn't get here, but flagged just ini case. */
- errorflg = ERRSYNTAX;
- return(-1);
- break;
- }
- (*n)++; /* pop number stack */
- (*o)++; /* pop operator stack */
- return(0);
- }
-
- /* -------------------------------------------------------------------- */
-
- /*
- * Function declarations.
- */
- double sin();
- double cos();
- double atan();
- double log();
- double tan();
- double fact();
- double exp();
-
- /* --------------------------------------------------------------------- */
- /* SOME EXTRA FUNCTIONS */
- /* --------------------------------------------------------------------- */
- double _int(num)
- double num;
- {
- long trunc;
- trunc=num;
- num=trunc;
- return(num);
- }
- /* --------------------------------------------------------------------- */
- double sqroot(num)
- double num;
- {
- if(num < 0.0)
- {
- errorflg = ERRSQRT;
- }
- return(pow(num, 0.5));
- }
-
- /* --------------------------------------------------------------------- */
- /*
- * Abosulute value
- */
- double absolute(num)
- double num;
- {
- double fabs();
- return(fabs(num));
- }
-
- /* --------------------------------------------------------------------- */
- /*
- * Random number generator.
- */
- double rndgen(num)
- double num;
- {
- double rndnum;
- rndnum = rand();
- return((rndnum/32767.0) * num + 1);
- }
-
- /* --------------------------------------------------------------------- */
- /*
- * Factorial
- */
- double fact(n)
- double n;
- {
- long l;
- double fact();
- l = n;
- if(l>33 || l<0L)
- {
- errorflg = ERRFACT;
- return(0.0);
- }
-
- if(l == 0 || l == 1)
- {
- return(1.0);
- }
- else
- {
- return(l*fact(l-1.0));
- }
- }
- /* --------------------------------------------------------------------- */
- /*
- * This is the math func string and routine
- * dispatch table. Each entry contains the text for the MATH FUNCTION
- * in question and the address of the routine which services it.
- */
- struct tbl
- {
- char *cmdtxt;
- double (*func)();
- };
- struct tbl mathtbl[] = {
- {"sin", sin},
- {"cos", cos},
- {"exp", exp},
- {"log", log},
- {"int", _int},
- {"sqr", sqroot},
- {"abs", absolute},
- {"atn", atan},
- {"rnd", rndgen},
- {"tan", tan},
- {"fact", fact},
- /* THIS STUFF NOT INCLUDED YET
- {"cot", cotang},
- {"clg", log10},
- {"sgn", sign},
- */
- {0, 0}
- };
- /* -------------------------------------------------------------------- */
- /*
- * ////// CALL MATH FUNCTION ////////
- *
- * callin format:
- * value = mathcall(string);
- *
- * where: value = floating point value returned by call
- * string = pointer to a null terminated string containong
- * the func text and expression within () -
- * i.e. "sin(EXPRESSION TEXT)"
- */
- double
- mathcall(s)
- char s[];
- {
- char funnam[10]; /* func name copied from 's'
- used for string search */
- register char *x; /* pointer to paren enclosed expression */
- double evalx(),
- value, /* final value returned */
- exvalue; /* value of expression before being operated
- upon by the math func */
- register int i; /* index reg. for expediency */
-
- x = s; /* set pointer to func string */
- /*
- * copy the func name part up to the '('
- * to use for a string search in the table of names
- */
- for(i=0; *x != '(' ;)
- {
- funnam[i++] = *x++;
- }
-
- funnam[i] = '\0'; /* null terminate */
-
- /*
- * compare each string in table with funnam
- * when match is found, call using offset code
- * if end-of-table (null) encountered return 0
- */
- for(i=0; mathtbl[i].cmdtxt != 0 ; i++)
- {
- if(!(strcmp(funnam, mathtbl[i].cmdtxt)))
- {
- x++;
- exvalue = evalx(x);
- /* Call the function!! */
- value = (*mathtbl[i].func)(exvalue);
- return(value);
- }
- }
- errorflg = ERRFUNC; /* unknown math function */
- return(0.0); /* Return zero for unknown math functions */
- }
-